const TorrentModel = require('../models/torrent-model')
const ClientModel = require('../models/client-model')
const LibraryModel = require('../models/library-model')
const BtClients = require('../utils/btclients/index')

const SubService = require('../services/sub-service')
const MediaService = require('../services/media-service')

const path = require('path')
const fs = require('fs')
const { fileExists, padNumber } = require('../utils/common')

const logger = require('../utils/console-logger')

const schedule = require('node-schedule');

const { sendNotify } = require('../utils/notify');

const  scheduleCronstyle = async ()=>{

  logger.log('自动链接服务启动.');
  //每分钟的第10分钟定时执行一次:
  schedule.scheduleJob('0 0/10 * * * *', autoLinkFunc);

  // process.on('SIGINT', function () {
  //   logger.log('AutoLinkTimer Shutdown.'); 
  //   schedule.gracefulShutdown().then(() => process.exit(0))
  // })
}

let auto = true;

const turnOn = () => {
  auto = true;
  logger.log('AutoLinkTimer Turn On.');
}

const turnOff = () => {
  auto = false;
  logger.log('AutoLinkTimer Turn Off.');
}

if (!auto) {
  logger.info('自动链接服务已关闭.');
  return
}

async function autoLinkFunc(dryRun) {
  logger.log('AutoLinkTimer:' + new Date());

  //1.查找需要自动硬链接的种子
  const whereBuilder = modelQuery => {
    modelQuery.where('auto_link', 1)
    modelQuery.where('status', 'linked')
    // modelQuery.whereNull('link_dir')
  }
    
  let torrents = await TorrentModel.list(TorrentModel.buildPaging({}), whereBuilder, 15)

  torrents = torrents.filter(model => {return (model.clientid && model.hashString)})
  logger.log('Torrents to auto link:')
  // torrents.forEach((t,index) => logger.log(`${index+1}.${t.name}`))
  if (torrents.length > 0) {
    let tips = ''
    let todoNum = 0
    let tmdbids = new Set()
    for (let index = 0; index < torrents.length; index++) {
      const torrent = torrents[index];
      logger.log(`${index+1}.${torrent.name}`)
      let data;
      try {
        data = await prepareLink(torrent)
      } catch (error) {
        logger.error(error.message);
      }
      // 只返回处理文件列表，不执行硬链接
      if (dryRun===true) {
        logger.info("dryRun 模式");
        logger.debug(data);
        return data;
      }
      if (data) {
        if (torrent.tmdbid) tmdbids.add(torrent.tmdbid)
        todoNum++
        tips += `${todoNum}.${torrent.name}\n`
        const {message} = await doLink(data)
        message.forEach((t) => {
          logger.log(`- ${t}`)
          tips += `- ${t}\n`
        })
      }
      
    }

    // logger.log(tips)
    if (todoNum>0) {
      sendNotify('TorrentManager 通知', '🎉您的媒体库更新啦!\n' + tips)
      // 同步媒体库信息 延迟几分钟 保证媒体库刮削完成
      setTimeout(() => {
        SubService.syncFromMediaServerByTmdbids([...tmdbids])
      }, 5 * 60 * 1000)
    }
  } else {
    logger.log('Empty')
    return { message: 'Empty' };
  }
  
}

var MATCH_FILES = /.mp4$|.mkv$|.avi$|.ts$/;
async function prepareLink(model) {
  let data

  // 没有媒体信息，不处理
  if (!model.tmdbid) {
    throw new Error(`还未识别媒体信息: ${model.id}.${model.name}`)
  }

  const media = await MediaService.getMedia(model.tmdbid, model.mediaType, false)
  const mediaInfo = media && media.info ? JSON.parse(media.info) : null
  if (!mediaInfo) {
    throw new Error(`媒体信息缺失: ${model.id}.${model.name}`)
  }
  
  let libraryPath
  if (model.libraryid) {
    const library = await LibraryModel.getById(model.libraryid)
    if (library && library.folder) libraryPath = library.folder
  }
  // 没有目录，不处理
  if (!libraryPath) {
    throw new Error(`未设置媒体库: ${model.id}.${model.name}`)
  }

  const rawTitle = `${mediaInfo.title} (${mediaInfo.year.split('-')[0]})`
  const linkDir = libraryPath
  const clientModel = await ClientModel.getById(model.clientid)
  if (clientModel) {
    const client = BtClients.getClient(clientModel)
    try{
      const torrent = await client.getTorrent(model.hashString)
      if (torrent.leftUntilDone === 0) {
        data = {
          torrentId: model.id,
          sourceDir: path.join(clientModel.volumeContainer, torrent.downloadDir.replace(clientModel.volumeHost, '')), // volumeContainer volumeHost
          linkDir,
          files: torrent.files ? torrent.files : [],
        }
        data.linkRows = []
        data.files.forEach(r => {
          const suffixMatch = r.name.match(MATCH_FILES)
          if (suffixMatch) {
            const linkRow = {}
            linkRow.sourceFile = r.name
            linkRow.replace = false
            const simpleName = simplifyName(r.name)
            const seriesParsed = parseSeries(simpleName)
            if (seriesParsed.isSeries) {
              // 季数默认使用种子设置的，如果没有则使用识别的
              const season_number = model.season || seriesParsed.season
              linkRow.linkFile = path.join(model.toLink ? model.toLink : rawTitle, `Season ${padNumber(season_number, 2)}`, `S${padNumber(season_number, 2)}E${padNumber(seriesParsed.episode, 2)}${suffixMatch[0]}`)
            } else {
              linkRow.linkFile = model.toLink ? path.join(model.toLink, `${rawTitle}${suffixMatch[0]}`) : path.join(rawTitle, `${rawTitle}${suffixMatch[0]}`) //simpleName
            }
            data.linkRows.push(linkRow)
          } else {
            logger.log('>>>>>不支持的文件:', r.name)
          }
        })
      } else {
        logger.log(`${model.name}, 下载中...`)
      }
    }catch(e){
      logger.error(e);
    }
  }
  return data
}

function lawSeriesName() {

}

function simplifyName(pathName) {
  return pathName.replace(/\\/g, "/") // Support Windows slashes, lol
        .split("/")
        .reverse()[0]
}

function parseSeries(name) {
  const meta = {
    isSeries: false,
  }
  if (name) name.split(/\.| |_/).forEach(function(x, i){
      /*
      * S01E01
      */
      if (isNaN(meta.season) || isNaN(meta.episode)) {
        var seMatch = x.match(/S(\d{1,2})E(\d{1,3})/i);
        if (seMatch){
          // console.log(x,'seMatch', seMatch);
          meta.season = parseInt(seMatch[1], 10);
          meta.episode = parseInt(seMatch[2], 10);
        }
      }
      
      /**
       * e01 ep01
       */    
      if (isNaN(meta.season) || isNaN(meta.episode)) {
        var epMatch = x.match(/EP?(\d{1,3})/i);
        if (epMatch) {
          // console.log(x,'epMatch', epMatch);
          meta.season = 1
          meta.episode = parseInt(epMatch[1], 10) ;
        }

      }

      /**
       * sp01
       */      
      if (isNaN(meta.season) || isNaN(meta.episode)) {
        var spMatch = x.match(/SP(\d{1,3})/i);
        if (spMatch) {
          // console.log(x,'spMatch', spMatch);
          meta.season = 0
          meta.episode = parseInt(spMatch[1], 10);
        }
      }  
      
      /* 
      * 01x20
      */   
      if (isNaN(meta.season) || isNaN(meta.episode)) {
        var xStampMatch = x.match(/(\d\d?)x(\d\d?)/i);
        if (xStampMatch){
          // console.log(x,'xStampMatch', xStampMatch);
          meta.season = parseInt(xStampMatch[1], 10);
          meta.episode = parseInt(xStampMatch[2], 10);
        }
      } 
      // if (otherCardMatch)
  });

  if (!isNaN(meta.season) && !isNaN(meta.episode)) meta.isSeries = true

  return meta
}

async function doLink(data) {
  const { torrentId, sourceDir, linkDir, linkRows, move=false } = data
  // console.log('torrentId', torrentId)
  // console.log('sourceDir', sourceDir)
  // console.log('linkDir', linkDir)
  // console.log('linkRows', linkRows)
  // console.log('move', move)
  let autoLinked = {message:[]}
  if (torrentId && sourceDir && linkDir && linkRows) {
    let sourceNotExists = 0
    let targetExists = 0
    let success = 0
    for (let index = 0; index < linkRows.length; index++) {
        const linkRow = linkRows[index]
        // 原文件
        const sourceFile = path.join(sourceDir, linkRow.sourceFile)
        // 目标文件
        const linkFile = path.join(linkDir, linkRow.linkFile)

        logger.log('%s\n-> %s', sourceFile, linkFile)
        // continue
        
        if (await fileExists(sourceFile)) {
            if (await fileExists(linkFile) && !linkRow.replace) {
              targetExists++
              // logger.log('目标已存在') 
            } else {
              fs.rmSync(linkFile, { force: true })
              fs.mkdirSync(path.dirname(linkFile), { recursive: true })
              if (move === true) {
                  // 移动
                  fs.renameSync(sourceFile, linkFile)
              } else {
                  // 硬连接
                  fs.linkSync(sourceFile, linkFile)
              }
              success++ //+= `${linkRow.linkFile}, `
              // logger.log('硬链接成功')
            }
        } else {
          sourceNotExists++
          // logger.log('原文件不存在')
        }
    }
    if(sourceNotExists>0)autoLinked.message.push(`原文件不存在,${sourceNotExists}`)
    if(targetExists>0)autoLinked.message.push(`目标已存在,${targetExists}`)
    autoLinked.message.push(`媒体文件新增: ${success}`)
  } else {
    autoLinked.message.push(`链接失败: torrentId:${torrentId}, sourceDir:${sourceDir}, linkDir:${linkDir}, linkRowsLength:${linkRows.length}.`)
  }
  // 记录种子最近链接
  TorrentModel.updateBy({ linkDir: linkDir, autoLink: 0 }, { id: torrentId })
  return autoLinked
}

function test() {
  const name = 'A.Lifelong.Journey.2022.EP136.V2.1080p.WEB-DL.HEVC.AAC-DBTV.mp4'
  const suffixMatch = name.match(MATCH_FILES)
  if (suffixMatch) {
    const simpleName = simplifyName(name)
    const seriesParsed = parseSeries(simpleName)
    console.log(seriesParsed);
    if (seriesParsed.isSeries) {
      console.log(path.join(`Season ${seriesParsed.season}`, `S${padNumber(seriesParsed.season, 2)}E${padNumber(seriesParsed.episode, 2)}${suffixMatch[0]}`));
    } else {
      console.log(simpleName);
    }
  } else {
    console.log('>>>>>不支持的文件:', name)
  }
}

module.exports = { scheduleCronstyle, autoLinkFunc, turnOn, turnOff }